home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / Libraries / PNL Libraries / MyFMenus.p < prev    next >
Encoding:
Text File  |  1995-10-23  |  8.9 KB  |  373 lines  |  [TEXT/CWIE]

  1. unit MyFMenus;
  2.  
  3. { From Peter's PNL Libraries }
  4. { Copyright 1992 Peter N Lewis }
  5. { This source may be used for any non-commercial purposes as long as I get a mention }
  6. { in the About box and Docs of any derivative program.  It may not be used in any commercial }
  7. { application without my permission }
  8.  
  9. interface
  10.  
  11.     uses
  12.         Menus, Events, MyCallProc;
  13.  
  14.     type
  15.         FMenuMenuProc = procedure(themenu,theitem:integer);
  16.         FMenuCommandProc = procedure;
  17.         
  18.     var
  19.         thefmenu, thefitem: integer;
  20.         menu_modifiers: integer;
  21.  
  22.     procedure StartupFMenus;
  23.     procedure ConfigureFMenus (default: FMenuMenuProc);
  24.  
  25.     function GetFMenu (id: integer): MenuHandle;
  26. { Call this in place of GetMenu, to read in an fmnu resource.  Use InsertMenu to add it to the menu bar }
  27.     procedure SetFCommand (command: OSType; cmdproc: FMenuCommandProc);
  28. { Call this to associate a procedure with a command OSType }
  29.     procedure SetFSetMenu (command: OSType; smproc: FMenuMenuProc);
  30. { procedure smproc(themenu,theitem:integer) }
  31. { Call this to associate a procedure for enabling/disabling the menu item }
  32.     procedure SetFBoth (command: OSType; cmdproc: FMenuCommandProc; smproc: FMenuMenuProc);
  33. { This is just a short form to set both the command and SetMenu procedures }
  34.  
  35.     function DoFMenuKey (var er: EventRecord): longInt;
  36. { Calls SetFMenus and then MDEF_MenuKey }
  37.     procedure SetFMenus;
  38. { Call this before MenuKey or MenuSelect to set the enables of all the menus }
  39.     procedure SetFMenu (themenu: integer);
  40. { Call this to set the enables of all the items in themenu }
  41.     procedure DoFMenu (themenu, theitem: integer);
  42. { Call this to act on a menu selection from either MenuSelect or MenuKey }
  43.  
  44. { You probably won't need these }
  45.     procedure AddFCommand (themenu, theitem: integer; command: OSType);
  46. { Call this to associate a menu item with an OSType - normally done by GetFMenu }
  47.     procedure GetCommand (themenu, theitem: integer; var command: OSType);
  48. { Call this to figure out what command OSType is associated with a menu item - normally done via DoFMenu }
  49.     procedure DoCommand (themenu, theitem: integer; command: OSType);
  50. { Call this to execute a menu command - normally done via DoFMenu }
  51.  
  52. implementation
  53.  
  54.     uses
  55.         Resources, Script, 
  56.         BaseGlobals,MyCallProc, MyMemory, MyStartup;
  57.  
  58.     const
  59.         min_menu_time = 6;
  60.  
  61.     type
  62.         fmenuHeader = record
  63.                 visible: integer;
  64.                 count: integer;
  65.                 unknown1: integer;
  66.                 menuID: integer;
  67.                 unknown2: integer;
  68.                 unknown3: integer;
  69.                 name: str63;
  70.             end;
  71.         fmenuHeaderPtr = ^fmenuHeader;
  72.         fmenuItem = packed record
  73.                 command: OSType;
  74.                 mark: char;
  75.                 unknown2: byte;
  76.                 cmdKey: char;
  77.                 disabled: byte;
  78.                 name: str63;
  79.             end;
  80.         fmenuItemPtr = ^fmenuItem;
  81.         convertRecord = record
  82.                 menu, item: integer;
  83.                 cmd: OSType;
  84.                 cmdp: FMenuCommandProc;
  85.                 smp: FMenuMenuProc;
  86.             end;
  87.         convertArray = array[1..1000] of convertRecord;
  88.         convertPtr = ^convertArray;
  89.         convertHandle = ^convertPtr;
  90.  
  91.     var
  92.         convert_count: integer;
  93.         converts: convertHandle;
  94.         DefaultMenuProc: FMenuMenuProc;
  95.  
  96.     procedure AddFCommand (themenu, theitem: integer; command: OSType);
  97.     begin
  98.         if BAND(convert_count, 7) = 0 then begin
  99.             SetHandleSize(handle(converts), (convert_count + 8) * SizeOf(convertRecord));
  100.         end;
  101.         convert_count := convert_count + 1;
  102.         with converts^^[convert_count] do begin
  103.             menu := themenu;
  104.             item := theitem;
  105.             cmd := command;
  106.             cmdp := nil;
  107.             smp := nil;
  108.         end;
  109.     end;
  110.  
  111.     procedure NextPtr (var p: univ ptr; sp: univ ptr);
  112.     begin
  113.         p := ptr(longInt(sp) + sp^ + 2 - ord(odd(sp^)));
  114.     end;
  115.  
  116.     function GetFMenu (id: integer): MenuHandle;
  117.         var
  118.             h: handle;
  119.             mh: menuHandle;
  120.             ph: fmenuHeaderPtr;
  121.             p: fmenuItemPtr;
  122.             s: string[70];
  123.             i: integer;
  124.     begin
  125.         h := GetResource('fmnu', id);
  126.         HLock(h);
  127.         ph := fmenuHeaderPtr(h^);
  128.         mh := NewMenu(ph^.menuID, ph^.name);
  129.  
  130.         NextPtr(p, @ph^.name);
  131.         for i := 1 to ph^.count do begin
  132.             if p^.name = '-' then begin
  133.                 AppendMenu(mh, '(-');
  134.             end else begin
  135.                 AddFCommand(ph^.menuID, i, p^.command);
  136.                 s := p^.name;
  137.                 if p^.mark <> chr(0) then begin
  138.                     s := concat(s, '!', p^.mark);
  139.                 end;
  140.                 if p^.cmdKey <> chr(0) then begin
  141.                     s := concat(s, '/', p^.cmdKey);
  142.                 end;
  143.                 if p^.disabled = 1 then begin
  144.                     s := concat('(', s);
  145.                 end;
  146.                 AppendMenu(mh, s);
  147.             end;
  148.             NextPtr(p, @p^.name);
  149.         end;
  150.         ReleaseResource(h);
  151.  
  152.         GetFMenu := mh;
  153.     end;
  154.  
  155.     procedure FindMenu (themenu, theitem: integer; var i: integer);
  156.     begin
  157.         i := 1;
  158.         while i <= convert_count do begin
  159.             with converts^^[i] do begin
  160.                 if (menu = themenu) and (item = theitem) then begin
  161.                     Exit(FindMenu);
  162.                 end;
  163.             end;
  164.             i := i + 1;
  165.         end;
  166.         i := -1;
  167.     end;
  168.  
  169.     procedure SetFCommand (command: OSType; cmdproc: FMenuCommandProc);
  170.         var
  171.             i: integer;
  172.     begin
  173.         for i := 1 to convert_count do begin
  174.             with converts^^[i] do begin
  175.                 if cmd = command then begin
  176.                     cmdp := cmdproc;
  177.                 end;
  178.             end;
  179.         end;
  180.     end;
  181.  
  182.     procedure SetFSetMenu (command: OSType; smproc: FMenuMenuProc);
  183.         var
  184.             i: integer;
  185.     begin
  186.         for i := 1 to convert_count do begin
  187.             with converts^^[i] do begin
  188.                 if cmd = command then begin
  189.                     smp := smproc;
  190.                 end;
  191.             end;
  192.         end;
  193.     end;
  194.  
  195.     procedure SetFBoth (command: OSType; cmdproc: FMenuCommandProc; smproc: FMenuMenuProc);
  196.         var
  197.             i: integer;
  198.     begin
  199.         for i := 1 to convert_count do begin
  200.             with converts^^[i] do begin
  201.                 if cmd = command then begin
  202.                     cmdp := cmdproc;
  203.                     smp := smproc;
  204.                 end;
  205.             end;
  206.         end;
  207.     end;
  208.  
  209.     procedure GetCommand (themenu, theitem: integer; var command: OSType);
  210.         var
  211.             i: integer;
  212.     begin
  213.         FindMenu(themenu, theitem, i);
  214.         if i = -1 then begin
  215.             command := 'xxx0';
  216.         end else begin
  217.             command := converts^^[i].cmd;
  218.         end;
  219.     end;
  220.  
  221.     procedure DoCmd (themenu, theitem: integer; cmdp: FMenuCommandProc);
  222.     begin
  223.         thefmenu := themenu;
  224.         thefitem := theitem;
  225.         if cmdp = nil then begin
  226.             DefaultMenuProc(themenu, theitem);
  227.         end else begin
  228.             cmdp;
  229.         end;
  230.     end;
  231.  
  232.     procedure DoCommand (themenu, theitem: integer; command: OSType);
  233.         var
  234.             cmdproc: FMenuCommandProc;
  235.             i: integer;
  236.     begin
  237.         cmdproc := nil;
  238.         i := 1;
  239.         while i <= convert_count do begin
  240.             with converts^^[i] do begin
  241.                 if cmd = command then begin
  242.                     cmdproc := cmdp;
  243.                     leave;
  244.                 end;
  245.             end;
  246.             i := i + 1;
  247.         end;
  248.         DoCmd(themenu, theitem, cmdproc);
  249.     end;
  250.  
  251.     procedure DoFMenu (themenu, theitem: integer);
  252.         var
  253.             i: integer;
  254.             t: longInt;
  255.             tmp_hack: FMenuCommandProc;
  256.     begin
  257.         t := TickCount;
  258.         FindMenu(themenu, theitem, i);
  259.         if i = -1 then begin
  260.             DoCmd(themenu, theitem, nil);
  261.         end else begin
  262.             tmp_hack := converts^^[i].cmdp;
  263.             DoCmd(themenu, theitem, tmp_hack);
  264.         end;
  265.         if not quitNow then begin
  266.             t := TickCount - t;
  267.             if t < min_menu_time then begin
  268.                 Delay(min_menu_time - t, t);
  269.             end;
  270.             HiliteMenu(0);
  271.         end;
  272.     end;
  273.  
  274.     procedure SetFMenus;
  275.         var
  276.             i: integer;
  277.             dummy: boolean;
  278.             er: EventRecord;
  279.     begin
  280.         dummy := OSEventAvail(everyEvent, er);
  281.         menu_modifiers := er.modifiers;
  282.         for i := 1 to convert_count do begin
  283.             with converts^^[i] do begin
  284.                 if smp <> nil then begin
  285.                     smp(menu, item);
  286.                 end;
  287.             end;
  288.         end;
  289.     end;
  290.  
  291.     function DoFMenuKey (var er: EventRecord): longInt;
  292.         const
  293.             kMaskVirtualKey = $0000FF00; {get virtual key from event message}
  294.             kMaskASCII1 = $00FF0000;
  295.             kMaskASCII2 = $000000FF; {get key from KeyTrans return}
  296.             kKeyUpMask = $0080;
  297.         var
  298.             h: handle;
  299.             virtualKey, keyCId, state, keyInfo: longInt;
  300.             keycode: integer;
  301.             lowchar, highchar: integer;
  302.             ch: Char;
  303.     begin
  304.         ch := chr(BAND(er.message, $FF));
  305.         if BAND(er.modifiers, optionKey + controlKey) <> 0 then begin
  306.             virtualKey := BSR(BAND(er.message, kMaskVirtualKey), 8);
  307.             keyCode := BOR(BOR(BAND(er.modifiers, BNOT(optionKey + controlKey)), kKeyUpMask), virtualKey);
  308.             state := 0;
  309.  
  310.             keyCId := GetScriptVariable(GetScriptManagerVariable(smKeyScript), smScriptKeys);
  311.             h := GetResource('KCHR', keyCId);
  312.  
  313.             if h <> nil then begin
  314.                 HLock(h); { KeyTrans won't move memory, but lock it anyway to avoid any purging or foolishness }
  315.                 keyInfo := KeyTranslate(h^, keyCode, state);
  316.                 ReleaseResource(h);
  317.                 LowChar := BAND(keyInfo, $FF);
  318.                 HighChar := BAND(BSR(keyInfo, 16), $FF);
  319.                 if lowChar <> 0 then begin
  320.                     ch := chr(lowChar);
  321.                 end;
  322.                 if highChar <> 0 then begin
  323.                     ch := chr(highChar);
  324.                 end;
  325.             end;
  326.         end;
  327.         DoFMenuKey := MenuKey(ch);
  328.     end;
  329.  
  330.     procedure SetFMenu (themenu: integer);
  331.         var
  332.             i: integer;
  333.             dummy: boolean;
  334.             er: EventRecord;
  335.     begin
  336.         dummy := OSEventAvail(everyEvent, er);
  337.         menu_modifiers := er.modifiers;
  338.         for i := 1 to convert_count do begin
  339.             with converts^^[i] do begin
  340.                 if (themenu = menu) & (smp <> nil) then begin
  341.                     smp(menu, item);
  342.                 end;
  343.             end;
  344.         end;
  345.     end;
  346.  
  347.     function InitFMenus (var msg: integer): OSStatus;
  348.     begin
  349.         msg := msg; { Unused }
  350.         convert_count := 0;
  351.         InitFMenus := MNewHandle(converts, 0);
  352.     end;
  353.  
  354.     procedure FinishFMenus;
  355.     begin
  356.         DisposeHandle(handle(converts));
  357.     end;
  358.  
  359.     procedure ConfigureFMenus (default: FMenuMenuProc);
  360.     begin
  361.         if default = nil then begin
  362.             default := DoFMenu;
  363.         end;
  364.         DefaultMenuProc := default;
  365.     end;
  366.     
  367.     procedure StartupFMenus;
  368.     begin
  369.         SetStartup(InitFMenus, nil, 0, FinishFMenus);
  370.     end;
  371.     
  372. end.
  373.